module LogParser
	def self.do_parse(filename, options = {})
		default_options = { :skip_params => ["password"] }
		options = default_options.merge options
		unless options[:skip_params].is_a?(Array)
			options[:skip_params] = [options[:skip_params]]
		end
		print "reading: #{filename}\n|"
		start_time = Time.now
		log_entry = nil
		log_entry_count = 0
		line_number = 0
		
		File.open(filename) do |file|
			file.each_line do |line|
				line_number += 1
				begin
					if line[0..9] == "Processing"
						# Processing line gives controller, action, IP address, date/time, and HTTP method
						log_entry = LogEntry.new
						line = line[11..-1]
						controller_name, action_name = line[0..line.index(' ')].strip.split("#")
						logged_controller = LoggedController.find_or_create_by_name(controller_name)
						logged_action = LoggedAction.find_or_create_by_name_and_controller_id(action_name, logged_controller.id)
						log_entry.logged_action = logged_action
					
						line = line[line.index(' ')..-1].strip
						parts = line.split		# gives us ["(for", "11.1.111.11", "at", "2007-10-18", "15:22:51)", "[POST]"]
						ip_address = parts[1]
						date = parts[3]
						yr, mo, dy = date.split("-")
						time = parts[4]
						hr, mi, se = time.split(":")
						logged_ip_address = LoggedIpAddress.find_or_create_by_ip_address(ip_address)
						log_entry.logged_ip_address = logged_ip_address
					
						log_entry.accessed_at = Time.local yr, mo, dy, hr, mi, se
						log_entry.http_method = parts[5][1..-2]
					elsif line.strip[0..10] == "Session ID:" and log_entry
						# this line is session ID only
						log_entry.logged_session = LoggedSession.find_or_create_by_session_id(line.strip[11..-1].strip)
					elsif line.strip[0..10] == "Parameters:" and log_entry
						# this line is the parameter hash
						log_entry.params = eval(line.strip[11..-1].strip)
						
						# delete any params that might be sensitive or extraenous
						(options[:skip_params] + ["controller", "action"]).each do |param| 
							log_entry.params.each do |k,v|
								log_entry.params[k].delete(param.to_s) if log_entry.params[k].is_a?(Hash)
							end	
							log_entry.params.delete(param.to_s) 
						end
					elsif line[0..8] == "Completed" and log_entry
						# read the Completed line and pick out Completed, DB, and Rendering times, and HTTP status code
						parts = line.split("|")
						completed_part = parts.detect { |p| p.include? "Completed" }
						render_part = parts.detect { |p| p.include? "Rendering" }
						db_part = parts.detect { |p| p.include? "DB" }
						http_part = parts.detect { |p| p.include? "http" }
						
						log_entry.completion_time_in_secs = completed_part ? completed_part[13..completed_part.index("(")-1].strip : nil
						log_entry.render_time_in_secs = render_part ? render_part[render_part.index(":")+1..render_part.index("(")-1].strip : nil
						log_entry.db_time_in_secs = db_part ? db_part[db_part.index(":")+1..db_part.index("(")-1].strip : nil
						log_entry.http_status = http_part ? http_part.strip.split.first : nil
						done = true
						log_entry_count += 1
						print "="
					end
					
					if log_entry and done
						log_entry.save unless options[:read_only]
						log_entry = nil
						done = false
					end
				rescue Exception => e
					puts "\n#{e.to_s} raised while reading line number #{line_number}"
				end
			end
		end
		time_in_seconds = Time.now - start_time
		time_to_parse = time_in_seconds > 300 ? "#{(time_in_seconds / 60).to_i} minutes" : "#{time_in_seconds} seconds"
		print "|\nParse finished in #{time_to_parse}. #{log_entry_count} entries read. "
		puts options[:read_only] ? "No changes to database made." : "All log entries imported into #{ENV['RAILS_ENV'] || 'development'} database."
	end
	
end
